#!/bin/sh

#  tinyPNG.py
#  KwSing
#
#  Created by zg.shao on 14-9-9.
#  Copyright (c) 2014 kuwo.cn. All rights reserved.

#!python
#encoding:utf-8

import sys
import os
import urllib2
import socket
from hashlib import md5
from base64 import b64encode

g_inputDir = ''
g_minSize = 0

class PngItemsMgr:
	fileList = []
	fileSize = 0
	md5FilePath = ''
	
	api_key = "y5iBwFqasRslcympCPXRd6yhvBZP508E"
	api_url = "https://api.tinypng.com/shrink"
	
	def __init__(self):
		pass
		self.md5FilePath = os.path.join(os.getcwd(), 'pngMD5.txt')
	
	def convertBytes(self, byte_count):
		tb = 1099511627776.0
		gb = 1073741824.0
		mb = 1048576.0
		kb = 1024.0
		
		if byte_count >= tb:
			return '%.2f TB' % (byte_count / tb)
		elif byte_count >= gb:
			return '%.2f GB' % (byte_count / gb)
		elif byte_count >= mb:
			return '%.2f MB' % (byte_count / mb)
		elif byte_count >= kb:
			return '%.2f KB' % (byte_count / kb)
		else:
			return '%.2f Bytes' % (byte_count)
			
	def isPngFile(self, filePath):
		image_format = ['.PNG']
		if filePath and (os.path.splitext(filePath)[1].upper() in image_format):
			return True
		return False
	
	def getFileMD5(self, filePath):
		m = md5()
		a_file = open(filePath, 'rb')
		m.update(a_file.read())
		a_file.close()
		return m.hexdigest()
	
	def tinyPng(self, filePath, outputFilePath):
		request = urllib2.Request(self.api_url, open(filePath, 'rb').read())
		
		cafile = None
		
		auth = b64encode(bytes("api:" + self.api_key)).decode()
		request.add_header("Authorization", "Basic %s" % auth)
		
		socket.setdefaulttimeout(2*60)
		try:
			response = urllib2.urlopen(request, cafile)
		except Exception,data:
			print Exception,":",data
			return {}
			
		if response.getcode() == 201:
			resp = response.read()
			dict = eval(resp)
			result = urllib2.urlopen(dict['output']['url'], cafile, 3*60).read()
			open(outputFilePath, 'wb').write(result)
			return dict
		else:
			print 'compress %s error!' % filePath
			return {}
			
	def findPngFile(self, dirr):
		filters = self.loadMD5String()
		for item in os.listdir(dirr):
			newItem = os.path.join(dirr, item)
			if os.path.isdir(newItem):
				self.findPngFile(newItem)
			elif os.path.isfile(newItem) and self.isPngFile(newItem):
				global g_minSize
				tmpSize = os.path.getsize(newItem)
				md5String = self.getFileMD5(newItem)
				if tmpSize > g_minSize:
					dst = os.path.join(dirr, '20140909_tiny_' + item);
					dict = {'src':newItem, 'dst':dst}
					dict['md5'] = md5String
					if md5String in filters:
						dict['handle_flag'] = 1
					else:
						dict['handle_flag'] = 0
					self.fileList.append(dict)
	
	def handleAllPngFiles(self):
		print 'find %d files' % len(self.fileList)
		index = 1
		for dict in self.fileList:
			print 'compressing %d file...' % index
			index += 1
			if dict['handle_flag'] == 1:
				continue

			print dict['src']
			resultDict = self.tinyPng(dict['src'], dict['dst'])
			if len(resultDict) > 1:
				dict['ori_size'] = resultDict['input']['size']
				dict['cur_size'] = resultDict['output']['size']
				dict['ratio'] = resultDict['output']['ratio']
				dict['md5'] = self.getFileMD5(dict['dst'])

				self.saveMD5String(dict['md5'])
				print 'Result: ori_size=%d, cur_size=%d, ratio=%.3f' % (dict['ori_size'], dict['cur_size'], dict['ratio'])
				
				os.remove(dict['src'])
				os.rename(dict['dst'], dict['src'])
				
	def saveMD5String(self, md5Str):
		file_content = self.loadMD5String()

		file_obj = open(self.md5FilePath, 'a+')
		if len(file_content) > 0:
			file_obj.write(':')
		file_obj.write(md5Str)
		file_obj.close()
	
	def loadMD5String(self):
		retArray=[]
		if os.path.exists(self.md5FilePath):
			file_obj = open(self.md5FilePath, 'r')
			file_content = file_obj.read()
			retArray=file_content.split(':')
			file_obj.close()
			return retArray
		return []
								
	def printResult(self):
		for dict in self.fileList:
			print dict
		tmpSize = self.fileSize
		if tmpSize % 1024 > 0:
			tmpSize
		print 'find', len(self.fileList), 'file,allSize:', self.convertBytes(self.fileSize)
			
# // end class

def checkParams(argv):
	if len(argv) == 2 and (not cmp(argv[1], '-help') or not cmp(argv[1], '-version')):
		return True
	elif len(argv) == 3 and not cmp(argv[1], '-d'):
		if os.path.exists(argv[2]):
			global g_inputDir
			g_inputDir = argv[2]
			return True
		else:
			print argv[2] + 'not exists'
			return False
	elif len(argv) == 4 and ((not cmp(argv[1], '-d') and not cmp(argv[3], '-min')) or (not cmp(argv[1], '-min') and not cmp(argv[3], '-d'))):
		if not cmp(argv[1], '-d'):
			if os.path.exists(argv[2]):
				return True
			else:
				print argv[2] + 'not exists'
				return False
		else:
			if os.path.exists(argv[4]):
				return True
			else:
				print argv[4] + 'not exists'
				return False
	return False
	
if __name__ == '__main__':
#	if not checkParams(sys.argv):
#		usage(sys.argv)
#		exit()
#	pngMgr = PngItemsMgr()
#	pngMgr.findPngFile(g_inputDir)
#	pngMgr.printResult()
#	pngMgr.tinyPng('/Users/dev/Desktop/KuwoSing/KwSing/KwSing/opensource/Umeng/umFeedback.bundle/img/titleBar.png', '/Users/dev/Desktop/shao.png')
	mypath = os.path.join(os.getcwd(), 'Images.xcassets')
	pngMgr = PngItemsMgr()
	pngMgr.findPngFile(mypath)
	pngMgr.handleAllPngFiles()
#	pngMgr.printResult()
